﻿//++
//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
// Module Name:
//
//  ExchangeTask.cs
//    
// Abstract:
//
//  This module implements the ExchangeTask class. This is the base class for any of the EWS tasks.
//
//--

using System;
using System.Diagnostics;

using Microsoft.OfficeCommunicationsServer.Applications.Common;

namespace Microsoft.EnhancedReminders.Scheduler
{
    /// <summary>
    /// This is the base class for any of the EWS tasks.
    /// </summary>
    internal abstract class ExchangeTask : Task
    {
        // WCF proxy for communicating with EWS
        protected readonly ExchangeServicePortType _client;

        // Impersonation details for this task
        protected readonly ExchangeImpersonationType _impersonation;

        // Mailbox address for this task
        protected readonly string _emailAddress;

        /// <summary>
        /// ctor.
        /// </summary>
        /// <param name="taskContext">Task context</param>
        /// <param name="client">WCF proxy for communicating with EWS</param>
        /// <param name="impersonation">Exchange impersonation info</param>
        /// <param name="emailAddress">E-mail address of the user associated with this task</param>
        protected ExchangeTask(TaskContext taskContext, ExchangeServicePortType client, ExchangeImpersonationType impersonation, string emailAddress)
            : base(taskContext)
        {
            Debug.Assert(client != null, "client != null");
            Debug.Assert(!String.IsNullOrEmpty(emailAddress), "!String.IsNullOrEmpty(emailAddress)");

            _client = client;
            _impersonation = impersonation;
            _emailAddress = emailAddress;
        }

        /// <summary>
        /// Delegate used to get the response when an asynchronous EWS request completes.
        /// </summary>
        /// <typeparam name="T">Type of response</typeparam>
        /// <param name="asyncResult">The result of the asynchronous EWS request</param>
        /// <returns>
        /// The response or null if the request was unsuccessful.
        /// </returns>
        internal delegate T GetResponseDelegate<T>(IAsyncResult asyncResult);

        /// <summary>
        /// Extracts the EWS response from the specified async result.
        /// </summary>
        /// <typeparam name="T">The type of response</typeparam>
        /// <param name="asyncResult">The result of the asynchronous EWS request</param>
        /// <param name="getResponseDelegate">Method to invoke to extract the response</param>
        /// <param name="message">Logging message to be associated with any errors</param>
        /// <returns>
        /// The response or null if the request was unsuccessful.
        /// </returns>
        protected T GetResponse<T>(IAsyncResult asyncResult, GetResponseDelegate<T> getResponseDelegate, string message)
        {
            T response = default(T);

            try
            {
                // Get the response
                response = getResponseDelegate(asyncResult);
                Debug.Assert(response != null, "response != null");
            }
            catch (Exception ex)
            {
                HandleAccessError(ex, message);
            }
            finally
            {
                asyncResult.AsyncWaitHandle.Close();
            }

            return response;
        }

        /// <summary>
        /// Handles errors accessing EWS.
        /// </summary>
        /// <param name="ex">Error</param>
        /// <param name="message">Diagnostic log message</param>
        /// <remarks>
        /// This method is invoked whenever there is an error accessing EWS.
        /// </remarks>
        protected void HandleAccessError(Exception ex, string message)
        {
            Debug.Assert(ex != null, "ex != null");
            Debug.Assert(!String.IsNullOrEmpty(message), "!String.IsNullOrEmpty(message)");

            Logger.WriteTraceError(Context, ex, message);
            OperationalLogs.LogMailboxItemAccessError(_emailAddress, ex);
            Helpers.FilterIrrecoverableExceptions(ex);
            RaiseCompleted(new TaskCompletedEventArgs(_taskContext, ex));
        }
    }
}
